package com.elitesland.metadata.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.elitesland.core.base.PagingVO;
import com.elitesland.core.exception.BusinessException;
import com.elitesland.metadata.convert.MetaFieldConvert;
import com.elitesland.metadata.entity.QMetaFieldDO;
import com.elitesland.metadata.param.MetaFieldQParam;
import com.elitesland.metadata.param.MetaFieldSaveParam;
import com.elitesland.metadata.repo.MetaFieldRepo;
import com.elitesland.metadata.service.MetaFieldService;
import com.elitesland.metadata.vo.MetaFieldVO;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <pre>作用说明</pre>
 *
 * @author mir
 * @date 11/21/2020 2:39 AM
 */
@Service
public class MetaFieldServiceImpl implements MetaFieldService {

    private MetaFieldRepo metaFieldRepo;

    @Autowired
    public void setMetaFieldRepo(MetaFieldRepo metaFieldRepo) {
        this.metaFieldRepo = metaFieldRepo;
    }

    private final QMetaFieldDO metaFields = QMetaFieldDO.metaFieldDO;

    @Async()
    @Override
    public CompletableFuture<PagingVO<MetaFieldVO>> search(MetaFieldQParam param) {

        return CompletableFuture.<PagingVO<MetaFieldVO>>supplyAsync(() -> {

            Predicate predicate = metaFields.isNull().or(metaFields.isNotNull());

            predicate = CollUtil.isEmpty(param.getIds()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.id.in(param.getIds()));
            predicate = StrUtil.isBlank(param.getFieldCode()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.fieldCode.like("%" + param.getFieldCode() + "%"));
            predicate = StrUtil.isBlank(param.getFieldDesc()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.fieldCode.like("%" + param.getFieldDesc() + "%"));
            predicate = StrUtil.isBlank(param.getFieldType()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.fieldType.eq(param.getFieldType()));
            predicate = param.getFieldLength() == null ? predicate :
                    ExpressionUtils.and(predicate, metaFields.fieldLength.eq(param.getFieldLength()));
            predicate = param.getFieldPrecision() == null ? predicate :
                    ExpressionUtils.and(predicate, metaFields.fieldPrecision.eq(param.getFieldPrecision()));
            predicate = StrUtil.isBlank(param.getUdcDomainCode()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.udcDomainCode.eq(param.getUdcDomainCode()));
            predicate = StrUtil.isBlank(param.getUdcCode()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.udcCode.eq(param.getUdcCode()));
            predicate = StrUtil.isBlank(param.getPageElement()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.pageElement.eq(param.getPageElement()));
            predicate = StrUtil.isBlank(param.getPageLabel()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.pageLabel.like("%" + param.getPageLabel() + "%"));
            predicate = StrUtil.isBlank(param.getMobileElement()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.mobileElement.eq(param.getMobileElement()));
            predicate = StrUtil.isBlank(param.getMobileLabel()) ? predicate :
                    ExpressionUtils.and(predicate, metaFields.mobileLabel.like("%" + param.getMobileLabel() + "%"));
            predicate = param.getIsRequired() == null ? predicate :
                    ExpressionUtils.and(predicate, metaFields.isRequired.eq(param.getIsRequired()));
            predicate = param.getMaxLength() == null ? predicate :
                    ExpressionUtils.and(predicate, metaFields.maxLength.eq(param.getMaxLength()));
            predicate = param.getMinLength() == null ? predicate :
                    ExpressionUtils.and(predicate, metaFields.minLength.eq(param.getMinLength()));

            val ret = metaFieldRepo.findAll(predicate, param.getPageRequest());

            return PagingVO.<MetaFieldVO>builder()
                    .total(ret.getTotalElements())
                    .records(ret.getContent().stream().map(MetaFieldConvert.INSTANCE::doToVO)
                            .collect(Collectors.toList()))
                    .build();
        });

    }

    @Async
    @Override
    public CompletableFuture<Optional<MetaFieldVO>> oneById(Long id) {
        return CompletableFuture.supplyAsync(() -> metaFieldRepo.findById(id).map(MetaFieldConvert.INSTANCE::doToVO));
    }

    @Override
    public CompletableFuture<List<MetaFieldVO>> listByIds(List<Long> ids) {
        return CompletableFuture.supplyAsync(() ->
                metaFieldRepo.findAllByIdIn(ids).stream().map(MetaFieldConvert.INSTANCE::doToVO)
                        .collect(Collectors.toList())
        );
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public CompletableFuture<Long> create(MetaFieldSaveParam metaField) {
        return CompletableFuture.supplyAsync(() -> {
            val oldFieldOpt = metaFieldRepo.findByFieldCode(metaField.getFieldCode());
            if (oldFieldOpt.isPresent()) {
                throw new BusinessException("字段：" + metaField.getFieldCode() + ", 已经存在");
            }

            val newField = metaFieldRepo.save(MetaFieldConvert.INSTANCE.saveToDO(metaField));
            return newField.getId();
        });
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void update(MetaFieldSaveParam metaField) throws BusinessException {
        metaFieldRepo.findById(metaField.getId()).ifPresentOrElse(mf -> {
            mf.setFieldDesc(metaField.getFieldDesc())
                    .setFieldLength(metaField.getFieldLength())
                    .setFieldType(metaField.getFieldType())
                    .setFieldLength(metaField.getFieldLength())
                    .setFieldPrecision(metaField.getFieldPrecision())
                    .setUdcDomainCode(metaField.getUdcDomainCode())
                    .setUdcCode(metaField.getUdcCode())
                    .setUdcDefaultDesc(metaField.getUdcDefaultDesc())
                    .setPageElement(metaField.getPageElement())
                    .setPageLabel(metaField.getPageLabel())
                    .setMobileElement(metaField.getMobileElement())
                    .setMobileLabel(metaField.getMobileLabel())
                    .setIsRequired(metaField.getIsRequired())
                    .setMinLength(metaField.getMinLength())
                    .setMaxLength(metaField.getMaxLength());

            metaFieldRepo.save(mf);
        }, () -> {
            throw new BusinessException("记录未找到，无法更新");
        });
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void removeById(Long id) {
        metaFieldRepo.deleteById(id);
    }
}
